﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Windows.Forms;
using System.Threading;
using ArtMath.Command;
using ArtMath.CommonType;
using ArtMath.Component;
using ArtMath.Setting;
using ArtMath.Core.Data;
using ArtMath.Component.CoordinateSystem;
using ArtMath.Control;
using ArtMath.Component.Point;
using ArtMath.AuxiliaryTool;
using ArtMath.Animation;
using ArtMath.Component.Manager;
using ArtMath.Resource;
using ArtMath.Attribute;
using ArtMath.Core.Helper;
using ArtMath.Converter;
using ArtMath.Component.CoordinateSystem.Converter;
using ArtMath.PointCollection;
using ArtMath.PointCollection.Helper;
using ArtMath.Flag;
using ArtMath.Data;
using System.Collections;
using System.Drawing.Printing;
using ArtMath.Parameter;
using ArtMath.Component.Annotation;
using ArtMath.Component.Interface;
using ArtMath.CommonType.Converter;

namespace ArtMath
{
    [Serializable]
    public partial class SketchPad : ICommandHistory, IRecoverableDelete, ISerializable, IObjectPickable, IActivate
    {
        [Serializable]
        class AbsorbedObjectsComparer : IComparer<Base>
        {
            public int Compare(Base x, Base y)
            {
                if (ReferenceEquals(x, y)) return 0;
                PointBase rp1 = x as PointBase;
                if (rp1 != null)
                {
                    PointBase rp2 = y as PointBase;
                    if (rp2 != null)
                    {
                        return rp1.OrderIndex - rp2.OrderIndex;
                    }
                    else
                    {
                        return -1;
                    }
                }
                else
                {
                    return 1;
                }
            }
        }
        SmoothingMode qua = Settings.Instance.PictureQuality;
        [Browsable(false)]
        public Document Document { get; }
        RPointS translate;
        public PointD OldPLocation, NewPLocation;
        public CoordinateBase Coordinate, OldCoordinate;
        [NonSerialized]
        LayerControl layer;
        [Browsable(false)]
        public LayerControl Layer { get { return layer; } }
        [NonSerialized]
        ToolTypeName selectedToolType = ToolTypeName.zz;
        public Point OldMouseEventLocation, NewMouseEventLocation;
        //[Browsable(false)]
        //public StringBuilder EventReporters { get; } = new StringBuilder();
        string name;
        Base hostObj, trackObj;
        AngleUnit angleUnit = AngleUnit.Degree;
        bool fsMode;
        public event Action AngleUnitChanged;
        [NonSerialized]
        public ToolBase ToolObj;
        //[Browsable(false)]
        //public Ring Ring { get { return FunctionTrackObj as Ring; } }
        [Browsable(false)]
        public LayerItem LayerItem { get; }
        [NonSerialized]
        ListViewItem thumbNailItem;
        [Browsable(false)]
        public ListViewItem ThumbNailItem { get { return thumbNailItem; } }
        [NonSerialized]
        Stack<ICommand> undos = new Stack<ICommand>();
        [NonSerialized]
        Stack<ICommand> redos = new Stack<ICommand>();
        [Browsable(false)]
        public List<CalculatedParameter> Parameters { get; } = new List<CalculatedParameter>();
        [Browsable(false)]
        public HashSet<PointBase> PointFlags { get; } = new HashSet<PointBase>();
        //[Browsable(false)]
        //public Stack<PointBase> ProcessingPoint { get; } = new Stack<PointBase>();
        [Browsable(false)]
        public HashSet<LineBase> LineFlags { get; } = new HashSet<LineBase>();
        [Browsable(false)]
        public List<AnimationBase> Animations { get; } = new List<AnimationBase>();
        [Browsable(false)]
        public SortedSet<Base> AbsorbedObjects { get; } = new SortedSet<Base>(new AbsorbedObjectsComparer());
        [Browsable(false)]
        public HashSet<PropertyDisplayer> AbsorbedPropertyDisplayers { get; } = new HashSet<PropertyDisplayer>();
        Dictionary<Base, StyleState> styleBackup = new Dictionary<Base, StyleState>();
        [Browsable(false)]
        public HashSet<Base> SelectedObjects { get; } = new HashSet<Base>();
        [Browsable(false)]
        public bool IsActivated { get; private set; }
        public bool UseReversedColor;
        [Browsable(false)]
        public ObjectState ObjectState { get; private set; } = ObjectState.Normal;
        [NonSerialized]
        ListViewItem recycleItem;
        [Browsable(false)]
        public ListViewItem RecycleItem { get { return recycleItem; } }
        readonly object moveLocker = new object();
        //[NonSerialized]
        //System.Timers.Timer changeInvertionState;
        //[Browsable(false)]
        //public System.Timers.Timer ChangeInvertionState
        //{
        //    get { return changeInvertionState; }
        //    private set
        //    {
        //        if (changeInvertionState != null)
        //        {
        //            changeInvertionState.Elapsed -= ChangeInvertionState_Elapsed;
        //        }
        //        changeInvertionState = value;
        //        if (changeInvertionState != null)
        //        {
        //            changeInvertionState.Elapsed += ChangeInvertionState_Elapsed;
        //        }
        //    }
        //}
        public int PointOrder = 0;
        [Browsable(false)]
        public LabelLocationManager ParameterLocationManager { get; }
        public PointAbsorb PointAbsorbMode = PointAbsorb.Auto;
        public event Action<SketchPad> NameChanged, CoordinateSystemChanged, Activated;
        public event Action<SketchPad, ICommand> NewCommandAdded, Undid, Redid;
        public event Action<SketchPad, PointD?> CurrentCoordinateChanged;
        public event Action<SketchPad, ToolStrip> ToolStripCreated;
        Point mouseDownLocation;
        Size oldSize;
        #region TabPageControls
        [NonSerialized]
        TabPage tabPage;
        [Browsable(false)]
        public TabPage TabPage { get { return tabPage; } }
        [NonSerialized]
        CanvasBox canvas;
        [Browsable(false)]
        public CanvasBox Canvas { get { return canvas; } }
        [NonSerialized]
        Panel topPanel;
        [NonSerialized]
        Label msgLabel;
        [NonSerialized]
        PictureBox msgClose;
        [NonSerialized]
        Thread countDownThread;
        #endregion
        public SketchPad(Document doc, string name)
        {
            //ChangeInvertionState = new System.Timers.Timer(Settings.Instance.FlashInterval == 0 ? 700 : Settings.Instance.FlashInterval);
            Document = doc;
            layer = new LayerControl(this);
            BuildTabPage();
            LayerItem = new LayerItem(Resources.Translate("Canvas"), null);
            Layer.Add(LayerItem);
            thumbNailItem = new ListViewItem() { Tag = this };
            Location = new RPointS(this);
            Zoom = new RPointS(this, "100%", "100%");
            //Ring = new Ring(this);
            ParameterLocationManager = new LabelLocationManager();
            Document.Pads.Add(this);
            Name = name;
        }
        [Browsable(false)]
        public ToolTypeName SelectedToolType
        {
            get { return selectedToolType; }
            set
            {
                if (selectedToolType == value) return;
                if (HostObj != null)
                {
                    PenBase pen = HostObj as PenBase;
                    if (pen != null)
                    {
                        pen.Complete();
                    }
                    else
                    {
                        HostObj.Delete();
                    }
                }
                selectedToolType = value;
                switch (selectedToolType)
                {
                    case ToolTypeName.zz:
                        Canvas.Cursor = Cursors.Default;
                        Flags.CursorVisible = true;
                        ToolObj = null;
                        break;
                    case ToolTypeName.zcx:
                    case ToolTypeName.zd:
                    case ToolTypeName.zx:
                    case ToolTypeName.sjxnx:
                    case ToolTypeName.sjxwx:
                    case ToolTypeName.sjxcx:
                    case ToolTypeName.dbxzx:
                    case ToolTypeName.wjy:
                    case ToolTypeName.nqy:
                    case ToolTypeName.ldjl:
                    case ToolTypeName.ddzxdjl:
                    case ToolTypeName.lzxjl:
                    case ToolTypeName.lxldslj:
                    case ToolTypeName.lxldxlj:
                    case ToolTypeName.jpfx:
                    case ToolTypeName.lzxjj:
                    case ToolTypeName.sdjd:
                    case ToolTypeName.lzxdj:
                    case ToolTypeName.csfc:
                    case ToolTypeName.dhs:
                    case ToolTypeName.jndfx:
                    case ToolTypeName.dbfd:
                    case ToolTypeName.hs:
                        Canvas.Cursor = Cursors.Default;
                        break;
                    case ToolTypeName.dxp:
                        PointEraser pe = new PointEraser()
                        {
                            Radius = Settings.Instance.PointEraserRadius / Math.Min(Zoom.X.Value, Zoom.Y.Value),
                        };
                        pe.Erase += (PointD pt) =>
                        {
                            ForEachExistVisibleObject((Base obj) =>
                            {
                                PenBase pen = obj as PenBase;
                                if (pen != null)
                                {
                                    for (int i = 0; i < pen.Paths.Count; i++)
                                    {
                                        for (int j = 0; i < pen.Paths.Count && j < pen.Paths[i].Count; j++)
                                        {
                                            if (pt.DistanceTo(pen.Paths[i][j]) <= Settings.Instance.PointEraserRadius)
                                            {
                                                pen.Split(i, j);
                                            }
                                        }
                                    }
                                    if (pen.IsEmpty)
                                    {
                                        pen.Delete();
                                    }
                                }
                                return true;
                            });
                        };
                        if (inCanvas && pe.Radius > 0)
                        {
                            Flags.CursorVisible = false;
                            pe.Visible = true;
                        }
                        ToolObj = pe;
                        break;
                    case ToolTypeName.qyxp:
                        Canvas.Cursor = new Cursor(Resource.Properties.Resources.eraser.GetHicon());
                        break;
                    case ToolTypeName.yzb:
                        Canvas.Cursor = new Cursor(Resource.Properties.Resources.pen.GetHicon());
                        break;
                    case ToolTypeName.ygb:
                        Canvas.Cursor = new Cursor(Resource.Properties.Resources.highlighter.GetHicon());
                        break;
                    case ToolTypeName.ydhb:
                        Canvas.Cursor = new Cursor(Resource.Properties.Resources.cursor_hand.GetHicon());
                        break;
                    case ToolTypeName.sf:
                        Canvas.Cursor = new Cursor((Flags.Shift ? Resource.Properties.Resources.zoom_out : Resource.Properties.Resources.zoom_in).GetHicon());
                        break;
                    case ToolTypeName.yddx:
                    case ToolTypeName.qhdlx:
                        SelectNothing();
                        Ring rng = new Ring()
                        {
                            Radius = Settings.Instance.RingRadius / Math.Min(Zoom.X.Value, Zoom.Y.Value),
                        };
                        if (inCanvas && rng.Radius > 0)
                        {
                            Flags.CursorVisible = false;
                            rng.Visible = true;
                        }
                        ToolObj = rng;
                        break;
                    default:
                        Canvas.Cursor = Cursors.Cross;
                        break;
                }
                Canvas_MouseMove(Canvas, new System.Windows.Forms.MouseEventArgs(MouseButtons.None, 0, NewMouseEventLocation.X, NewMouseEventLocation.Y, 0));
            }
        }
        public bool SuspendCreation()
        {
            if (HostObj == null) return false;
            try
            {
                HostObj.Delete();
            }
            catch (Exception)
            {
                return false;
            }
            TrackObj = null;
            return true;
        }
        public void Activate()
        {
            if (Document.IsActivated)
            {
                if (Document.SelectedPad != null)
                {
                    Document.SelectedPad.Deactivate();
                }
                IsActivated = true;
                if (Document.PageContainer.SelectedTab != TabPage)
                {
                    Document.PageContainer.SelectedTab = TabPage;
                }
                Activated?.Invoke(this);
                Layer.Activate();
            }
            else
            {
                Document.Activate();
            }
        }
        public void Print(PageSettings page = null, PrinterSettings printer = null)
        {
            PrintDocument doc = new PrintDocument()
            {
                DocumentName = $"{Name} [{Document.Title}]",
            };
            doc.PrintPage += (object sender, PrintPageEventArgs e) =>
            {
                Paint(e.Graphics);
            };
            PrintDialog dial = new PrintDialog()
            {
                Document = doc,
                UseEXDialog = true,
            };
            if (dial.ShowDialog() == DialogResult.OK)
            {
                if (page == null)
                {
                    PageSetupDialog psd = new PageSetupDialog()
                    {
                        Document = doc,
                    };
                    if (psd.ShowDialog() == DialogResult.OK)
                    {
                        doc.DefaultPageSettings = psd.PageSettings;
                        if (printer == null)
                        {
                            doc.PrinterSettings = psd.PrinterSettings;
                        }
                    }
                }
                else
                {
                    doc.DefaultPageSettings = page;
                }
                if (printer != null)
                {
                    doc.PrinterSettings = printer;
                }
                PrintPreviewDialog ppd = new PrintPreviewDialog()
                {
                    Document = doc,
                };
                if (ppd.ShowDialog() == DialogResult.OK)
                {
                    doc.Print();
                }
            }
        }
        [Browsable(false)]
        public bool CanRecover
        {
            get { return true; }
        }
        [Browsable(false)]
        public bool IsSelectedPad
        {
            get { return Document.SelectedPad == this; }
        }
        [Browsable(false)]
        public Base HostObj
        {
            get { return hostObj; }
            set
            {
                hostObj = value;
                if (hostObj != null)
                {
                    hostObj.SpareCoordinate_ = NewPLocation;
                }
            }
        }
        [Browsable(false)]
        public Base TrackObj
        {
            get { return trackObj; }
            set
            {
                trackObj = value;
                if (trackObj != null && HostObj != trackObj)
                {
                }
            }
        }
        [Browsable(false)]
        public SizeD PSize
        {
            get { return GetPSize(Canvas.ClientSize); }
        }
        [Browsable(false)]
        public Stack<ICommand> Undos
        {
            get { return undos; }
        }
        [Browsable(false)]
        public Stack<ICommand> Redos
        {
            get { return redos; }
        }
        public void OperateRing(Action<Ring> act)
        {
            if (act == null) return;
            Ring rng = ToolObj as Ring;
            if (rng == null) return;
            act(rng);
        }
        public Bitmap GetThumbNail()
        {
            Bitmap bmp = new Bitmap(Canvas.Width, Canvas.Height);
            Canvas.DrawToBitmap(bmp, new Rectangle(0, 0, Canvas.Width, Canvas.Height));
            Graphics gra = Graphics.FromImage(bmp);
            Paint(gra);
            return bmp;
        }
        /// <summary>
        /// 获取或设置当前画板的角度单位
        /// </summary>
        [MultilingualCategory("Preference"), MultilingualDisplayName(null, "Angle", "Unit"), TypeConverter(typeof(AngleUnitConverter)), DefaultValue(typeof(AngleUnit), "Degree")]
        public AngleUnit AngleUnit
        {
            get { return angleUnit; }
            set
            {
                if (angleUnit == value) return;
                angleUnit = value;
                AngleUnitChanged?.Invoke();
            }
        }
        [MultilingualCategory("Basic"), MultilingualDisplayName("Name")]
        public string Name
        {
            get { return name; }
            set
            {
                if (value != name)
                {
                    if (Document.CheckPadNameExist(value))
                    {
                        if (MessageBox.Show(string.Format(Resources.Translate("SketchpadNameExistInDocument"), value), Resources.Translate("Ask"), MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question) == DialogResult.Yes)
                        {
                            value = Utility.GetNextAvailableName(value, Document.CheckPadNameExist);
                        }
                        else
                        {
                            return;
                        }
                    }
                    name = value;
                }
                TabPage.Text = ThumbNailItem.Text = name;
                NameChanged?.Invoke(this);
            }
        }
        [MultilingualCategory("Layout"), MultilingualDisplayName("Size")]
        public Size Size
        {
            get { return Canvas.Size; }
            set { Canvas.Size = value; }
        }
        [MultilingualCategory("Layout"), DefaultValue(typeof(bool), "True"), MultilingualDisplayName("AdaptWorkspace"), TypeConverter(typeof(Converter.BooleanConverter))]
        public bool AdaptWorkspace
        {
            get { return Canvas.Dock == DockStyle.Fill; }
            set
            {
                Canvas.Dock = value ? DockStyle.Fill : DockStyle.None;
                Canvas.Invalidate();
            }
        }
        [MultilingualCategory("Appearance"), DefaultValue(typeof(Color), "White"), MultilingualDisplayName(null, "Background", "Color")]
        public Color BackgroundColor
        {
            get { return Canvas.BackColor ; }
            set { Canvas.BackColor = value; }
        }
        [MultilingualCategory("Appearance"), MultilingualDisplayName(null, "Background", "Image")]
        public Image BackgroundImage
        {
            get { return Canvas.BackgroundImage; }
            set { Canvas.BackgroundImage = value; }
        }
        [MultilingualCategory("Appearance"), MultilingualDisplayName(null, "Background", "Image", "Layout"), TypeConverter(typeof(ImageLayoutConverter)), DefaultValue(typeof(ImageLayout), "Tile")]
        public ImageLayout BackgroundImageLayout
        {
            get { return Canvas.BackgroundImageLayout; }
            set { Canvas.BackgroundImageLayout = value; }
        }
        [MultilingualCategory("View"), MultilingualDisplayName("QualityMode"), DefaultValue(typeof(SmoothingMode), "HighQuality"), TypeConverter(typeof(SmoothingModeConverter))]
        public SmoothingMode QualityMode
        {
            get { return qua; }
            set
            {
                qua = value;
                Canvas.Invalidate();
            }
        }
        [MultilingualCategory("Layout"), MultilingualDisplayName("Location"), DefaultValue(typeof(RPointS), "0, 0")]
        public RPointS Location
        {
            get { return translate; }
            set
            {
                if (translate != null)
                {
                    translate.CoordinateChanged -= Translate_CoordinateChanged;
                }
                translate = value;
                if (translate != null)
                {
                    translate.CoordinateChanged += Translate_CoordinateChanged;
                }
            }
        }
        [MultilingualCategory("Layout"), MultilingualDisplayName("Zoom"), DefaultValue(typeof(RPointS), "100%, 100%")]
        public RPointS Zoom { get; set; }
        [MultilingualCategory("Basic"), MultilingualDisplayName("CoordinateSystem"), TypeConverter(typeof(CoordinateSystemTypeConverter))]
        public CoordinateSystemType CoordinateType
        {
            get
            {
                if (Coordinate == null) return CoordinateSystemType.None;
                if (Coordinate.ToolType == ToolTypeName.zjzbx) return CoordinateSystemType.RectangularCoordinate;
                return CoordinateSystemType.PolarCoordinate;
            }
            set
            {
                ChangeCoordinate(value);
            }
        }
        [Browsable(false)]
        public double PointSelectorRadius
        {
            get
            {
                double res = 0;
                OperateRing((Ring rng) => { res = rng.Radius; });
                return res;
            }
        }
        [Browsable(false)]
        public SizeD CanvasPSize
        {
            get
            {
                return new SizeD(Canvas.ClientSize.Width / Zoom.X.Value, Canvas.ClientSize.Height / Zoom.Y.Value);
            }
        }
        [Browsable(false)]
        IEnumerable IObjectPickable.SelectedObjects
        {
            get { return SelectedObjects; }
        }
        [Browsable(false)]
        public bool FullScreenMode
        {
            get { return fsMode; }
            set
            {
                if (fsMode == value) return;
                fsMode = value;
                if (fsMode)
                {
                    BuildFullScreen();
                }
                else
                {
                    Form frm = Canvas.Parent as Form;
                    TabPage.Controls.Add(Canvas);
                    frm.Close();
                }
            }
        }
        void Translate_CoordinateChanged(PointD oldVal, PointD newVal)
        {
            RectangularCoordinate rc = Coordinate as RectangularCoordinate;
            if (rc != null)
            {
                rc.YAxis.GraduationTextLocation = translate.X + Coordinate.OriginCoordinate.X < 24 ?
                 AxisTextLocation.Below : AxisTextLocation.Above;
                rc.XAxis.GraduationTextLocation = translate.Y + Coordinate.OriginCoordinate.Y > Canvas.Height - 25 ?
                AxisTextLocation.Above : AxisTextLocation.Below;
            }
            else
            {
                PolarCoordinate pc = Coordinate as PolarCoordinate;
                if (pc != null)
                {
                    pc.PolarAxis.GraduationTextLocation = translate.Y + Coordinate.OriginCoordinate.Y > Canvas.Height - 25 ?
                    AxisTextLocation.Above : AxisTextLocation.Below;
                }
            }
        }
        //void Zoom_CoordinateChanged(PointD oldVal, PointD newVal)
        //{
        //    Console.WriteLine((Coordinate as RectangularCoordinate).XAxis.Min + " " + (Coordinate as RectangularCoordinate).XAxis.Max);
        //    ForEachObject((Base obj) =>
        //    {
        //        Function func = obj as Function;
        //        if (func != null)
        //        {
        //            func.BuildSamples();
        //        }
        //        return true;
        //    });
        //}
        public void ShowMessage(string msg, MessageType type)
        {
            msgLabel.Text = new string(' ', 4) + msg;
            switch (type)
            {
                case MessageType.Information:
                    topPanel.BackColor = Color.FromArgb(189, 215, 238);
                    msgLabel.ForeColor = Color.FromArgb(44, 97, 151);
                    msgLabel.Image = Resource.Properties.Resources.information;
                    break;
                case MessageType.Exclamation:
                    topPanel.BackColor = Color.FromArgb(255, 235, 156);
                    msgLabel.ForeColor = Color.FromArgb(156, 87, 0);
                    msgLabel.Image = Resource.Properties.Resources.exclamation;
                    break;
                case MessageType.Error:
                    topPanel.BackColor = Color.FromArgb(255, 199, 206);
                    msgLabel.ForeColor = Color.FromArgb(156, 0, 6);
                    msgLabel.Image = Resource.Properties.Resources.dialog_error;
                    break;
            }
            topPanel.Show();
            if (countDownThread != null && countDownThread.IsAlive)
            {
                countDownThread.Abort();
            }
            countDownThread = new Thread(() =>
            {
                Thread.Sleep(3000);
                topPanel.CrossThreadInvoke(() => { topPanel.Hide(); });
            })
            {
                IsBackground = true,
            };
            countDownThread.Start();
        }
        public SizeD GetPSize(SizeD sz)
        {
            return sz / Zoom.ToPointD();
        }
        public SizeD GetPSize(Size sz)
        {
            return new SizeD(sz.Width / Zoom.X.Value, sz.Height / Zoom.Y.Value);
        }
        public PointBase CreatePoint(string name, PointD Pxy, bool absorb = true, bool addToList = false)
        {
            return CreatePoint(name, Pxy, absorb, Universal.GenerateInstanceArray(), addToList);
        }
        public PointBase CreatePoint(string name, PointD Pxy, bool absorb, PointCollectionBase[] collections, bool addToList = false)
        {
            PointBase result;
            PointD XY = Coordinate == null ? Pxy : Coordinate.PxyToXY(Pxy);
            if (absorb && PointAbsorbMode != PointAbsorb.No)
            {
                List<ShapeBase> objs = new List<ShapeBase>();
                foreach (Base item in AbsorbedObjects)
                {
                    ShapeBase tmp = item as ShapeBase;
                    if (tmp != null)
                    {
                        objs.Add(tmp);
                    }
                }
                if (objs.Count > 0)
                {
                    switch (PointAbsorbMode)
                    {
                        case PointAbsorb.Auto:
                            if (objs.Count == 1)
                            {
                                result = objs[0] as PointBase;
                                if (result != null)
                                {
                                    if (collections.InPointCollections(result.ToPointD()))
                                    {
                                        HostTrackComponentBuilding(result.Pxy);
                                        return result;
                                    }
                                }
                                else
                                {
                                    LineBase line = objs[0] as LineBase;
                                    if (line != null)
                                    {
                                        PointD pxy = line.AttachedLocation, xy = PxyToXY(pxy);
                                        if (!collections.InPointCollections(xy))
                                        {
                                            PointCollectionBase[] targets = PointCollectionBase.Intersect(collections, line.Skeleton.PointCollections);
                                            if (targets == null) break;
                                            PointD? tmp = targets.GetNearestPoint(XY);
                                            if (tmp.HasValue)
                                            {
                                                pxy = XYToPxy(tmp.Value);
                                            }
                                            else
                                            {
                                                break;
                                            }
                                        }
                                        if (CoordinateType == CoordinateSystemType.PolarCoordinate)
                                        {
                                            if (Flags.Ctrl && SelectedToolType != ToolTypeName.zyd || SelectedToolType == ToolTypeName.zbd)
                                            {
                                                result = new PPoint_Fixed(this, name, addToList);
                                            }
                                            else
                                            {
                                                result = new PPoint(this, name, addToList);
                                            }
                                        }
                                        else
                                        {
                                            if (Flags.Ctrl && SelectedToolType != ToolTypeName.zyd || SelectedToolType == ToolTypeName.zbd)
                                            {
                                                result = new RPoint_Fixed(this, name, addToList);
                                            }
                                            else
                                            {
                                                result = new RPoint(this, name, addToList);
                                            }
                                        }
                                        result.SpareCoordinate = pxy;
                                        if (TryCreateObject(result))
                                        {
                                            result.OrderIndex = PointOrder++;
                                            result.OutHosts = new LineBase[1];
                                            if (Settings.Instance.FixOnConnectedLineGroup)
                                            {
                                                line.AllInHostsIterator((LineBase item) =>
                                                {
                                                    if (item.IsConnectedLineGroup)
                                                    {
                                                        result.SetLine(0, item);
                                                        return false;
                                                    }
                                                    return true;
                                                });
                                            }
                                            if (result.OutHosts[0] == null)
                                            {
                                                result.SetLine(0, line);
                                            }
                                            HostTrackComponentBuilding(result.Pxy);
                                            return result;
                                        }
                                    }
                                }
                            }
                            else
                            {
                                double minDist = double.PositiveInfinity;
                                PointD? minpt = null;
                                LineBase tg1 = null, tg2 = null;
                                for (int i = 0; i < objs.Count; i++)
                                {
                                    result = objs[i] as PointBase;
                                    if (result != null)
                                    {
                                        if (collections.InPointCollections(result.ToPointD()))
                                        {
                                            HostTrackComponentBuilding(result.Pxy);
                                            return result;
                                        }
                                    }
                                    else
                                    {
                                        LineBase line1 = objs[i] as LineBase;
                                        if (line1 != null)
                                        {
                                            for (int j = i + 1; j < objs.Count; j++)
                                            {
                                                LineBase line2 = objs[j] as LineBase;
                                                if (line2 == null) continue;
                                                PointCollectionsManager mgr = line1.Skeleton.Intersect(line2.Skeleton);
                                                if (mgr == null) continue;
                                                PointCollectionBase[] targets = PointCollectionBase.Intersect(mgr.PointCollections, collections);
                                                if (targets == null) continue;
                                                PointD? tmp = targets.GetNearestPoint(XY);
                                                if (tmp.HasValue)
                                                {
                                                    double dist = XY.DistanceTo(tmp.Value);
                                                    if (dist < minDist)
                                                    {
                                                        minDist = dist;
                                                        minpt = tmp.Value;
                                                        tg1 = line1;
                                                        tg2 = line2;
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                                if (tg1 != null && tg2 != null && minpt.HasValue)
                                {
                                    CrossoverPointsManager_B mgr = null;
                                    IEnumerable<ComponentManagerBase> jj = tg1.ComponentManagers.Intersect(tg2.ComponentManagers);
                                    foreach (ComponentManagerBase item in jj)
                                    {
                                        mgr = item as CrossoverPointsManager_B;
                                        if (mgr != null)
                                        {
                                            break;
                                        }
                                    }
                                    if (mgr != null || TryCreateObject(mgr = new CrossoverPointsManager_B(this, StdObjName("CrossoverPoint"), tg1, tg2)))
                                    {
                                        if (Coordinate != null) minpt = Coordinate.XYToPxy(minpt.Value);
                                        foreach (CrossoverPointBase item in mgr.Points)
                                        {
                                            if (item.Pxy.AlmostEquals(minpt.Value, false))
                                            {
                                                HostTrackComponentBuilding(item.Pxy);
                                                return item;
                                            }
                                        }
                                        if (CoordinateType == CoordinateSystemType.PolarCoordinate)
                                        {
                                            result = new PCrossoverPoint(this, name, tg1, tg2, mgr, addToList);
                                        }
                                        else
                                        {
                                            result = new RCrossoverPoint(this, name, tg1, tg2, mgr, addToList);
                                        }
                                        result.NewPxy = minpt.Value;
                                        if (TryCreateObject(result))
                                        {
                                            result.OrderIndex = PointOrder++;
                                            HostTrackComponentBuilding(result.Pxy);
                                            mgr.Points.Add(result as CrossoverPointBase);
                                            return result;
                                        }
                                    }
                                }
                            }
                            break;
                        case PointAbsorb.Ask:
                            //收集所有可吸附的对象
                            Dictionary<ShapeBase, PointD> dic = new Dictionary<ShapeBase, PointD>();
                            List<ListViewItem> items = new List<ListViewItem>();
                            foreach (ShapeBase item in objs)
                            {
                                PointD pxy = PointD.Empty;
                                result = item as PointBase;
                                if (result != null)
                                {
                                    if (collections.InPointCollections(result.ToPointD()))
                                    {
                                        pxy = result.Pxy;
                                    }
                                    else
                                    {
                                        continue;
                                    }
                                }
                                else
                                {
                                    LineBase line = item as LineBase;
                                    if (line != null)
                                    {
                                        pxy = line.AttachedLocation;
                                        PointD xy = PxyToXY(pxy);
                                        if (!collections.InPointCollections(xy))
                                        {
                                            PointCollectionBase[] targets = PointCollectionBase.Intersect(collections, line.Skeleton.PointCollections);
                                            if (targets == null) continue;
                                            PointD? tmp = targets.GetNearestPoint(XY);
                                            if (tmp.HasValue)
                                            {
                                                pxy = XYToPxy(tmp.Value);
                                            }
                                            else
                                            {
                                                continue;
                                            }
                                        }
                                    }
                                }
                                ListViewItem lvItem = new ListViewItem() { Text = item.Name, Tag = item, };
                                dic.Add(item, pxy);
                                lvItem.SubItems.Add(PxyToMath(pxy).ToString());
                                items.Add(lvItem);
                                if (Settings.Instance.FixOnConnectedLineGroup)
                                {
                                    item.AllInHostsIterator((LineBase line) =>
                                    {
                                        if (line.IsConnectedLineGroup)
                                        {
                                            lvItem = new ListViewItem() { Text = line.Name, Tag = line, };
                                            dic.Add(line, pxy);
                                            lvItem.SubItems.Add(PxyToMath(pxy).ToString());
                                            items.Add(lvItem);
                                            return false;
                                        }
                                        return true;
                                    });
                                }
                            }
                            //供选择（可选项坐标一定是符合要求的）
                            if (UIInteraction.CorrectCoordinate.CorrectCoordinate(name, PxyToMath(Pxy), items.ToArray()) == DialogResult.OK)
                            {
                                result = UIInteraction.CorrectCoordinate.SelectedPoint;
                                if (result != null)
                                {
                                    HostTrackComponentBuilding(dic[result]);
                                    return result;
                                }
                                else
                                {
                                    LineBase line = UIInteraction.CorrectCoordinate.SelectedLine;
                                    if (line != null)
                                    {
                                        if (CoordinateType == CoordinateSystemType.PolarCoordinate)
                                        {
                                            if (Flags.Ctrl && SelectedToolType != ToolTypeName.zyd || SelectedToolType == ToolTypeName.zbd)
                                            {
                                                result = new PPoint_Fixed(this, name, addToList);
                                            }
                                            else
                                            {
                                                result = new PPoint(this, name, addToList);
                                            }
                                        }
                                        else
                                        {
                                            if (Flags.Ctrl && SelectedToolType != ToolTypeName.zyd || SelectedToolType == ToolTypeName.zbd)
                                            {
                                                result = new RPoint_Fixed(this, name, addToList);
                                            }
                                            else
                                            {
                                                result = new RPoint(this, name, addToList);
                                            }
                                        }
                                        result.SpareCoordinate = dic[line];
                                        if (TryCreateObject(result))
                                        {
                                            result.OrderIndex = PointOrder++;
                                            result.OutHosts = new LineBase[1];
                                            result.SetLine(0, line);
                                            HostTrackComponentBuilding(result.Pxy);
                                            return result;
                                        }
                                    }
                                }
                            }
                            break;
                    }
                }
            }
            //不吸附：
            if (!collections.InPointCollections(XY))
            {
                PointD? tmp = collections.GetNearestPoint(XY);
                if (tmp.HasValue)
                {
                    XY = tmp.Value;
                    Pxy = XYToPxy(XY);
                }
            }
            if (CoordinateType == CoordinateSystemType.PolarCoordinate)
            {
                if (Flags.Ctrl && SelectedToolType != ToolTypeName.zyd || SelectedToolType == ToolTypeName.zbd)
                {
                    result = new PPoint_Fixed(this, name, addToList);
                }
                else
                {
                    result = new PPoint(this, name, addToList);
                }
            }
            else
            {
                if (Flags.Ctrl && SelectedToolType != ToolTypeName.zyd || SelectedToolType == ToolTypeName.zbd)
                {
                    result = new RPoint_Fixed(this, name, addToList);
                }
                else
                {
                    result = new RPoint(this, name, addToList);
                }
            }
            result.SpareCoordinate = Pxy;
            if (TryCreateObject(result))
            {
                result.OrderIndex = PointOrder++;
                HostTrackComponentBuilding(result.Pxy);
                return result;
            }
            throw new ComponentCreatingException(TrackObj as ShapeBase, "Fail");
        }
        /// <summary>
        /// 放大画板
        /// </summary>
        /// <param name="delta">放大的比例</param>
        public void ZoomIn(double delta)
        {
            Zoom.X.SetExpression((Zoom.X.Value + delta) * 100 + "%");
            Zoom.Y.SetExpression((Zoom.Y.Value + delta) * 100 + "%");
        }
        /// <summary>
        /// 缩小画板
        /// </summary>
        /// <param name="delta">缩小的比例</param>
        public void ZoomOut(double delta)
        {
            double newVal = Zoom.X.Value - delta;
            if (newVal > 0)
            {
                Zoom.X.SetExpression(newVal * 100 + "%");
            }
            newVal = Zoom.Y.Value - delta;
            if (newVal > 0)
            {
                Zoom.Y.SetExpression(newVal * 100 + "%");
            }
        }
        public bool TryCreateObject(Base obj)
        {
            if (obj == null || obj.IsCreationCompleted) return false;
            try
            {
                obj.CreateComponents();
            }
            catch (ComponentCreatingException ex)
            {
                ShowMessage(string.Format(Resources.Translate("FailedCreate"), ex.FailShape.Name, ex.Message), MessageType.Error);
                return false;
            }
            Canvas.Invalidate();
            return true;
        }
        public void CreateAndCommand(Base obj)
        {
            if (obj.IsCreationCompleted)
            {
                AddNewCommand(new AddObject<Base>(obj), false);
                HostObj = null;//针对创建点时
            }
            else
            {
                if (TryCreateObject(obj))
                {
                    if (obj.IsCreationCompleted)
                    {
                        AddNewCommand(new AddObject<Base>(obj), false);
                    }
                }
            }
        }
        public void Paint(Graphics gra)
        {
            gra.SmoothingMode = QualityMode;
            gra.TranslateTransform(translate.X.FloatValue, translate.Y.FloatValue);
            if (Coordinate != null)
            {
                gra.TranslateTransform(Coordinate.OriginCoordinate.X.FloatValue, Coordinate.OriginCoordinate.Y.FloatValue);
            }
            gra.ScaleTransform(Zoom.X.FloatValue, Zoom.Y.FloatValue);
            ForEachExistObject((Base obj) =>
            {
                ShapeBase sb = obj as ShapeBase;
                if (sb != null)
                {
                    sb.PaintTrack(gra);
                }
                obj.Paint(gra);
                obj.PaintProperties(gra);
                return true;
            }, true);
            if (HostObj != null)
            {
                HostObj.Paint(gra);
                HostObj.PaintVirtualObjects(gra);
                if (TrackObj != null && TrackObj != HostObj)
                {
                    TrackObj.PaintVirtualObjects(gra);
                }
            }
            ToolObj?.Paint(gra);
            gra.ResetTransform();
        }
        public void MoveObject_DoMouseDown(ShapeBase shape)
        {
            lock (moveLocker)
            {
                if (shape.PrepareMove())
                {
                    PointFlags.Clear();
                    //ProcessingPoint.Clear();
                    LineFlags.Clear();
                }
            }
        }
        public bool MoveObject_DoMouseMove(ShapeBase shape, PointD location)
        {
            lock (moveLocker)
            {
                try
                {
                    shape.Move(location);
                }
                catch (PointMovingException ex)
                {
                    if (ex.Message != Flags.ExceptionShieldMessage)
                    {
                        ShowMessage(string.Format(Resources.Translate("FailedMove"), ex.Message), MessageType.Error);
                    }
                    foreach (PointBase item in PointFlags)
                    {
                        item.BufferedMoveSpace = null;
                        item.NewPxy = item.Pxy;
                    }
                    PointFlags.Clear();
                    //ProcessingPoint.Clear();
                    return false;
                }
                finally
                {
                    LineFlags.Clear();
                }
                List<PointBase> waitMove = null;
                foreach (PointBase item in PointFlags)
                {
                    item.BufferedMoveSpace = null;
                    bool add = false;
                    item.AllRelatedObjectsIterator((Base obj) =>
                    {
                        if (obj.ObjectParameters.Count > 0)
                        {
                            add = true;
                        }
                        else
                        {
                            ShapeBase sb = obj as ShapeBase;
                            if (sb != null)
                            {
                                if (sb.CalculatedParameters.Count > 0)
                                {
                                    add = true;
                                }
                            }
                        }
                        return !add;
                    });
                    if (add || item.CalculatedParameters.Count > 0 || item.ObjectParameters.Count > 0)
                    {
                        if (waitMove == null)
                        {
                            waitMove = new List<PointBase>();
                        }
                        waitMove.Add(item);
                        continue;
                    }
                    item.ForceMove(item.NewPxy);
                }
                PointFlags.Clear();
                //ProcessingPoint.Clear();
                //含参点必须额外移动
                if (waitMove != null)
                {
                    foreach (PointBase item in waitMove)
                    {
                        item.ForceMove(item.NewPxy);
                    }
                }
                return true;
            }
        }
        public void MoveObject_DoMouseUp(ShapeBase shape)
        {
            lock (moveLocker)
            {
                if (shape.CleanMove())
                {
                    PointFlags.Clear();
                    //ProcessingPoint.Clear();
                    LineFlags.Clear();
                }
            }
        }
        public bool MovePoint(PointBase point, PointD destLocation)
        {
            MoveObject_DoMouseDown(point);
            bool res = MoveObject_DoMouseMove(point, destLocation);
            MoveObject_DoMouseUp(point);
            return res;
        }
        public void HostTrackComponentBuilding(PointD location)
        {
            if (TrackObj != null)
            {
                TrackObj.SpareCoordinate_ = location;
            }
            if (HostObj != null && HostObj != TrackObj)
            {
                if (TrackObj == null)
                {
                    HostObj.SpareCoordinate_ = location;
                }
                else
                {
                    HostObj.SpareCoordinate = location;
                    HostObj.ComponentBuilding(TrackObj);
                }
            }
            Canvas.Invalidate();
        }
        public void ClearAbsorbedObjects()
        {
            foreach (Base item in AbsorbedObjects)
            {
                item.StyleState = styleBackup[item];
            }
            AbsorbedObjects.Clear();
            styleBackup.Clear();
        }
        public void ClearAbsorbedPropertyDisplayers()
        {
            foreach (PropertyDisplayer item in AbsorbedPropertyDisplayers)
            {
                item.StyleState = StyleState.Normal;
            }
            AbsorbedPropertyDisplayers.Clear();
        }
        public void PropertyDisplayersCheckNearBy(PointD Plocation, bool checkSelected = false)
        {
            ClearAbsorbedPropertyDisplayers();
            foreach (LayerItem item in checkSelected ? Layer.SelectedItems : Layer.Items)
            {
                if (item.LinkedObj == null || item.ObjectState == ObjectState.Deleted) continue;
                PropertyDisplayer[] pds = item.LinkedObj.PropertyDisplayersCheckNearBy(Plocation);
                if (pds == null) continue;
                foreach (PropertyDisplayer pd in pds)
                {
                    if (AbsorbedPropertyDisplayers.Add(pd))
                    {
                        pd.StyleState = StyleState.Hover;
                    }
                }
            }
            Canvas.Invalidate();
        }
        /// <summary>
        /// 根据鼠标位置收集在鼠标附近的元件（点元件优先级最高，若有多个点，则order值最大的优先级最高）
        /// </summary>
        /// <param name="Plocation">鼠标位置</param>
        /// <param name="checkSelected">是否从列表选中项中查找</param>
        /// <param name="multiSelect">是否多选</param>
        public void CheckNearBy(PointD Plocation, bool checkSelected = false, bool multiSelect = false, Predicate<Base> judge = null)
        {
            ClearAbsorbedObjects();
            //if (!DoCheckNearBy) return;
            Base tmp = null;
            PointBase latestPoint = null;
            bool containsPoint = false, containsNonPoint = false;
            foreach (LayerItem item in checkSelected ? Layer.SelectedItems : Layer.Items)
            {
                if (item.LinkedObj == null || item.ObjectState == ObjectState.Deleted) continue;
                Base[] bs = item.LinkedObj.CheckNearBy(Plocation);
                if (bs == null) continue;
                foreach (Base obj in bs)
                {
                    if (multiSelect)
                    {
                        if (judge == null || judge(obj))
                        {
                            if (obj is PointBase)
                            {
                                if (AbsorbedObjects.Add(obj))
                                {
                                    containsPoint = true;
                                }
                                else
                                {
                                    continue;
                                }
                            }
                            else
                            {
                                if (!containsPoint && AbsorbedObjects.Add(obj))
                                {
                                    containsNonPoint = true;
                                }
                                else
                                {
                                    continue;
                                }
                            }
                            styleBackup.Add(obj, obj.StyleState);
                            obj.StyleState = StyleState.Hover;
                        }
                    }
                    else
                    {
                        PointBase pt = obj as PointBase;
                        if (pt != null)
                        {
                            if (latestPoint == null || pt.OrderIndex > latestPoint.OrderIndex)
                            {
                                latestPoint = pt;
                            }
                        }
                        else
                        {
                            tmp = obj;
                        }
                    }
                }
            }
            if (latestPoint != null)
            {
                if ((judge == null || judge(latestPoint)) && AbsorbedObjects.Add(latestPoint))
                {
                    containsPoint = true;
                    styleBackup.Add(latestPoint, latestPoint.StyleState);
                    latestPoint.StyleState = StyleState.Hover;
                }
            }
            else if (tmp != null && !containsPoint)
            {
                if ((judge == null || judge(tmp)) && AbsorbedObjects.Add(tmp))
                {
                    containsNonPoint = true;
                    styleBackup.Add(tmp, tmp.StyleState);
                    tmp.StyleState = StyleState.Hover;
                }
            }
            if (containsPoint && containsNonPoint)
            {
                HashSet<Base> removes = new HashSet<Base>();
                foreach (Base item in AbsorbedObjects)
                {
                    if (!(item is PointBase))
                    {
                        item.StyleState = styleBackup[item];
                        styleBackup.Remove(item);
                        removes.Add(item);
                    }
                }
                AbsorbedObjects.RemoveWhere((Base obj) => { return removes.Contains(obj); });
            }
            Canvas.Invalidate();
        }
        public void ChangeCoordinate(CoordinateSystemType targetCoordinateType, bool recoverable = false)
        {
            if (targetCoordinateType == CoordinateType) return;
            ChangeCoordinate(() =>
            {
                switch (targetCoordinateType)
                {
                    case CoordinateSystemType.RectangularCoordinate:
                        Coordinate = new RectangularCoordinate(this);
                        break;
                    case CoordinateSystemType.PolarCoordinate:
                        Coordinate = new PolarCoordinate(this);
                        break;
                }
                if (TryCreateObject(Coordinate))
                {
                    Coordinate.LayerItem.Index = 1;
                    if (OldCoordinate != null)
                    {
                        Coordinate.UseFormat(OldCoordinate);
                    }
                }
                else
                {
                    Coordinate = null;
                }
            }, recoverable);
        }
        public void ChangeCoordinate(Action changeCS, bool recoverable = false)
        {
            if (changeCS == null) return;
            OldCoordinate = Coordinate;
            Coordinate?.Delete(recoverable);
            Layer.ClickAfterAdd = false;
            changeCS();
            ParameterLocationManager.RegionRange = new RectangleD(MouseLocationToPxy(new Point(0, 0)), PSize);
            ForEachObject((Base obj) =>
            {
                obj.CoordinateSystemTypeChanged();
                return true;
            });
            Layer.ClickAfterAdd = true;
            CoordinateSystemChanged?.Invoke(this);
            OldCoordinate = null;
        }

        public void Undo(ICommand cmd)
        {
            if (undos.Count == 0) return;
            ICommand peek;
            do
            {
                peek = undos.Pop();
                peek.Undo();
                redos.Push(peek);
                Undid?.Invoke(this, peek);
            } while (undos.Count > 0 && peek != cmd);
        }

        public void Redo(ICommand cmd)
        {
            if (redos.Count == 0) return;
            ICommand peek;
            do
            {
                peek = redos.Pop();
                peek.Redo();
                undos.Push(peek);
                Redid?.Invoke(this, peek);
            } while (redos.Count > 0 && peek != cmd);
        }

        public void AddNewCommand(ICommand cmd, bool execute = true)
        {
            undos.Push(cmd);
            redos.Clear();
            NewCommandAdded?.Invoke(this, cmd);
            if (execute)
            {
                cmd.Redo();
            }
        }
        public void Undo()
        {
            if (undos.Count == 0) return;
            Undo(undos.Peek());
        }

        public void Redo()
        {
            if (redos.Count == 0) return;
            Redo(redos.Peek());
        }

        public void Delete(bool recoverable = false)
        {
            if (recoverable)
            {
                if (RecycleItem == null)
                {
                    recycleItem = new ListViewItem(new string[] { Name, Resources.Translate("Sketchpad") }) { Tag = this };
                }
                UIInteraction.RecycleBin.Delete(this);
                ObjectState = ObjectState.Deleted;
            }
            else
            {
                if (RecycleItem != null)
                {
                    RecycleItem.Remove();
                }
                Document.Pads.Remove(this);
                ObjectState = ObjectState.Disposed;
            }
            Document.PageContainer.TabPages.Remove(TabPage);
            ThumbNailItem.Remove();
        }

        public void Recover()
        {
            if (Document.CheckPadNameExist(Name))
            {
                DialogResult res = MessageBox.Show(string.Format(Resources.Translate("SketchpadNameExistInDocument"), Name), Resources.Translate("Ask"), MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
                switch (res)
                {
                    case DialogResult.Yes:
                        Name = Utility.GetNextAvailableName(Name, Document.CheckPadNameExist);
                        break;
                    case DialogResult.No:
                        return;
                    case DialogResult.Cancel:
                        throw new OperationCanceledException();
                }
            }
            Document.PageContainer.TabPages.Add(TabPage);
            Document.ThumbNailList.Items.Add(ThumbNailItem);
            RecycleItem.Remove();
            ObjectState = ObjectState.Normal;
        }

        public void BeforeSerializing(Dictionary<string, object> data)
        {
            Layer.BeforeSerializing(data);
            foreach (LayerItem item in Layer.Items)
            {
                if (item.LinkedObj == null) continue;
                item.LinkedObj.BeforeSerializing(data);
            }
            foreach (AnimationBase item in Animations)
            {
                item.BeforeSerializing(data);
            }
        }

        public void AfterDeserialized(Dictionary<string, object> data)
        {
            //ChangeInvertionState = new System.Timers.Timer(Settings.Instance.FlashInterval == 0 ? 700 : Settings.Instance.FlashInterval);
            oldCurveAccuracyExpression = new Dictionary<ICurve, string>();
            undos = new Stack<ICommand>();
            redos = new Stack<ICommand>();
            layer = new LayerControl(this);
            BuildTabPage();
            Layer.Add(LayerItem);
            Layer.AfterDeserialized(data);
            thumbNailItem = new ListViewItem() { Tag = this };
            Document.ThumbNailList.Items.Add(ThumbNailItem);
            if (ObjectState == ObjectState.Deleted)
            {
                recycleItem = new ListViewItem(new string[] { Name, Resources.Translate("Sketchpad") }) { Tag = this };
            }
            Name = Name;
            SelectedToolType = ToolTypeName.zz;
            foreach (LayerItem item in Layer.Items)
            {
                if (item.LinkedObj == null) continue;
                item.LinkedObj.AfterDeserialized(data);
            }
            foreach (AnimationBase item in Animations)
            {
                item.AfterDeserialized(data);
            }
        }

        public void SetObjectSelectionState(RectangleD rect)
        {
            rect = rect.ToStandardRectangle();
            ForEachExistVisibleObject((Base obj) =>
            {
                obj.CheckInRegion(rect);
                return true;
            });
        }
        public void Deactivate()
        {
            IsActivated = false;
            Layer.Deactivate();
        }
    }
}
